package com.jagochan.gateway.listener;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

@Slf4j
@RequiredArgsConstructor
@Component
public class NacosConfigInfoListener {

    private final NacosConfigManager nacosConfigManager;
    private final RouteDefinitionWriter routeDefinitionWriter;
    /**
     * 路由配置的routeId（用于当配置更新的时候删除之前的配置）
     */
    private final Set<String> routeIdSet = new HashSet<>();

    private static final String DATA_ID = "gatewayRoutes.json";
    private static final String GROUP = "DEFAULT_GROUP";

    @PostConstruct
    public void init() throws NacosException {
        ConfigService configService = nacosConfigManager.getConfigService();
        // 拉取配置信息，同时设置监听器
        String configInfo = configService.getConfigAndSignListener(DATA_ID, GROUP, 1000 * 60, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }

            @Override
            public void receiveConfigInfo(String configInfo) {
                // Nacos中的配置信息修改后，刷新gateway的路由表
                refreshRouteDefinitionTable(configInfo);
            }
        });
        // 第一次拉取配置信息后，把配置信息添加到gateway的路由表中
        refreshRouteDefinitionTable(configInfo);
    }

    private void refreshRouteDefinitionTable(String configInfo) {
        log.debug("刷新RouteDefinitionTable👉：{}", configInfo);

        // 删除之前的RouteDefinitionTable信息
        for (String routeId : routeIdSet) {
            routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();
        }
        routeIdSet.clear();

        // 把Nacos中的JSON格式的路由信息转换为RouteDefinition集合
        List<RouteDefinition> routeDefinitionList = JSONUtil.toList(configInfo, RouteDefinition.class);
        for (RouteDefinition routeDefinition : routeDefinitionList) {
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
            routeIdSet.add(routeDefinition.getId());
        }
    }

}

